#pragma once

#include "Comm.hpp"
#include "Util.hpp"
#include "HttpRequest.hpp"

enum RecvStatu
{
    RECV_HTTP_LINE, 
    RECV_HTTP_HEAD, 
    RECV_HTTP_BODY, 
    RECV_HTTP_OVER, 
    RECV_HTTP_ERROR, 
};

class HttpContext
{
private:
#define MAX_LINE_SIZE 8192 // 8 KB

    bool ParseHttpLine(const std::string& line)
    {
        std::smatch matches;
        std::regex e("(GET|HEAD|POST|PUT|DELETE) ([^?]*)(?:\\?(.*))? (HTTP/\\d{1}\\.\\d{1})(?:\n|\r\n)?", std::regex::icase);

        bool ret = std::regex_match(line, matches, e);
        if (ret == false) 
        {
            _recv_statu_proc = RECV_HTTP_ERROR;
            _resp_statu_code = 400;  // BAD REQUEST
            LOG(ERROR, "Match failure!\n");
            return false;
        }
        _request._method = matches[1];
        std::transform(_request._method.begin(), _request._method.end(), _request._method.begin(), ::toupper);
        _request._path = Util::UrlDecode(matches[2], false);
        // LOG(INFO, "_request._path: %s\n", _request._path.c_str());
        _request._version = matches[4];

        std::vector<std::string> queue_string;
        Util::Split(matches[3], "&", &queue_string);

        std::vector<std::string> key_val;
        for (auto& str : queue_string)
        {
            size_t ret = Util::Split(str, "=", &key_val);
            if (ret != 2)
            {
                _recv_statu_proc = RECV_HTTP_ERROR;
                _resp_statu_code = 400;  // BAD REQUEST
                LOG(ERROR, "The format of the query string is illegal\n");
            }
            _request.SetParmam(Util::UrlDecode(key_val[0], true), Util::UrlDecode(key_val[1], true));
            key_val.clear();
        }
        return true;
    }

    bool RecvHttpLine(Buffer* buf)
    {
        if ((_recv_statu_proc != RECV_HTTP_LINE) || (buf->GetSizeOfReadableData() == 0)) return false;
        
        std::string line;
        buf->GetLineAndPop(&line);
        if (line.size() == 0)
        {
            if (buf->GetSizeOfReadableData() > MAX_LINE_SIZE)
            {
                _recv_statu_proc = RECV_HTTP_ERROR;
                _resp_statu_code = 414;   // URI TOO LONG 
                LOG(ERROR, "URI TOO LONG!\n");
                return false;
            }
            return true;
        }
        else if (line.size() > MAX_LINE_SIZE)
        {
            _recv_statu_proc = RECV_HTTP_ERROR;
            _resp_statu_code = 414;   // URI TOO LONG 
            LOG(ERROR, "URI TOO LONG!\n");
            return false;
        }

        if (ParseHttpLine(line) == false) return false;
        // 首行处理完毕，进入头部获取阶段 
        _recv_statu_proc = RECV_HTTP_HEAD;
        return true;
    }

    bool ParseHttpHead(std::string& line)
    {
        if (line.back() == '\n') line.pop_back();
        if (line.back() == '\r') line.pop_back();
        size_t pos = line.find(": ");
        if (pos == std::string::npos)
        {
            _recv_statu_proc = RECV_HTTP_ERROR;
            _resp_statu_code = 400;   // BAD REQUEST 
            LOG(ERROR, "The format of the head is illegal!\n");
            return false;
        }
        std::string key = line.substr(0, pos);
        std::string val = line.substr(pos + 2);
        _request.SetHeader(key, val);
        return true;
    }

    bool RecvHttpHead(Buffer* buf)
    {        
        if (_recv_statu_proc != RECV_HTTP_HEAD) return false;
        while (1)
        {
            std::string line;
            buf->GetLineAndPop(&line);
            if (line.size() == 0)
            {
                if (buf->GetSizeOfReadableData() > MAX_LINE_SIZE)
                {
                    _recv_statu_proc = RECV_HTTP_ERROR;
                    _resp_statu_code = 414;   // URI TOO LONG 
                    LOG(ERROR, "URI TOO LONG!\n");
                    return false;
                }
                return true;
            }
            else if (line.size() > MAX_LINE_SIZE)
            {
                _recv_statu_proc = RECV_HTTP_ERROR;
                _resp_statu_code = 414;   // URI TOO LONG 
                LOG(ERROR, "URI TOO LONG!\n");
                return false;
            }

            if (line == "\r\n" || line == "\n") break;

            if (ParseHttpHead(line) == false) return false;
        }

        // 头部处理完毕，进入正文获取阶段 
        _recv_statu_proc = RECV_HTTP_BODY;
        return true;
    }
    
    bool RecvHttpBody(Buffer* buf)
    {
        if (_recv_statu_proc != RECV_HTTP_BODY) return false;
        size_t content_size = _request.GetContentSize();
        if (content_size == 0)
        {
            _recv_statu_proc = RECV_HTTP_OVER;
            return true;
        }
        
        size_t real_size = content_size - _request._body.size();
        if (buf->GetSizeOfReadableData() >= real_size)
        {
            _request._body.append(buf->GetReadPos(), real_size);
            buf->MoveReadBackward(real_size);
            _recv_statu_proc = RECV_HTTP_OVER;
            return true;
        }
        else
        {
            _request._body.append(buf->GetReadPos(), buf->GetSizeOfReadableData());
            buf->MoveReadBackward(buf->GetSizeOfReadableData());
            return true;
        }
    }

public:
    HttpContext() : _resp_statu_code(200), _recv_statu_proc(RECV_HTTP_LINE) {}

    void Reset() { _resp_statu_code = 200; _recv_statu_proc = RECV_HTTP_LINE; _request.Reset(); }

    int GetRespStatu() { return _resp_statu_code; }

    RecvStatu GetRecvStatu() { return _recv_statu_proc; }

    HttpRequest& GetRequ() { return _request; }

    // 接收并解析 HTTP 请求 
    void RecvHttpRequ(Buffer* buf)
    {
        if (buf->GetSizeOfReadableData() <= 0) return;
        // LOG(INFO, "buf: %s\n", buf->GetReadPos());
        switch (_recv_statu_proc)
        {
        case RECV_HTTP_LINE: RecvHttpLine(buf);
        case RECV_HTTP_HEAD: RecvHttpHead(buf);
        case RECV_HTTP_BODY: RecvHttpBody(buf);
        }
        return;
    }

private:
    int _resp_statu_code;        // 响应状态码 
    RecvStatu _recv_statu_proc;  // 接收以及解析的阶段状态 
    HttpRequest _request;        // 请求信息 
};

